home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Information / CSMP Digest / volume 2 / csmp-v2-005.txt < prev    next >
Text File  |  1995-06-30  |  43KB  |  1,130 lines

  1. C.S.M.P. Digest             Sat, 16 Jan 93       Volume 2 : Issue 5
  2.  
  3. Today's Topics:
  4.  
  5.     To (?) Evan Shandev - my stream search source
  6.     Free code:  Packing up strings into a STR#
  7.     Machine Icons
  8.     International Number Formats
  9.     midi help needed
  10.     Background your Sound!
  11.     Sound Input questions (real time usage)
  12.  
  13.  
  14.  
  15. The Comp.Sys.Mac.Programmer Digest is moderated by Michael A. Kelly.
  16.  
  17. The digest is a collection of article threads from the internet newsgroup
  18. comp.sys.mac.programmer.  It is designed for people who read c.s.m.p. semi-
  19. regularly and want an archive of the discussions.  If you don't know what a
  20. newsgroup is, you probably don't have access to it.  Ask your systems
  21. administrator(s) for details.  If you don't have access to news, there is
  22. no way that I know of for you to post articles to the group.
  23.  
  24. Each issue of the digest contains one or more sets of articles (called
  25. threads), with each set corresponding to a 'discussion' of a particular
  26. subject.  The articles are not edited; all articles included in this digest
  27. are in their original posted form (as received by our news server at
  28. cs.uoregon.edu).  Article threads are not added to the digest until the last
  29. article added to the thread is at least one month old (this is to ensure that
  30. the thread is dead before adding it to the digest).  Article threads that
  31. consist of only one message are generally not included in the digest.
  32.  
  33. The entire digest is available for anonymous ftp from ftp.cs.uoregon.edu
  34. [128.223.8.8] in the directory /pub/mac/csmp-digest.  Be sure to read the
  35. file /pub/mac/csmp-digest/README before downloading any files.  The most
  36. recent issues are available from sumex-aim.stanford.edu [36.44.0.6] in the
  37. directory /info-mac/digest/csmp.  If you don't have ftp capability, the sumex
  38. archive has a mail server; send a message with the text '$MACarch help' (no
  39. quotes) to LISTSERV@ricevm1.rice.edu for more information.
  40.  
  41. The digest is also available via email.  Just send a note saying that you
  42. want to be on the digest mailing list to mkelly@cs.uoregon.edu, and you will
  43. automatically receive each new issue as it is created.  Sorry, back issues
  44. are not available through the mailing list.
  45.  
  46. Send administrative mail to mkelly@cs.uoregon.edu.
  47.  
  48.  
  49. -------------------------------------------------------
  50.  
  51. From: urge@mcl.ucsb.edu (Scott Bronson)
  52. Subject: To (?) Evan Shandev - my stream search source
  53. Date: 14 Dec 92 05:04:11 GMT
  54.  
  55.  
  56. Sorry for butchering your name, but I forgot what it was exactly.
  57. I was forced to switch Email accounts, and in the move I lost my
  58. entire mail queue with your name and address safely tucked
  59. away.  I apologize for all this.
  60.  
  61. Anyway, I've decided to distribute this.  It's simply a cool
  62. little algorithm to search an incoming stream.  If you use this
  63. in one of your projects, I'd really like only one little thing
  64. in return: mail me and tell me how you use this source.
  65.  
  66. My original letter follows.  It first answers why I think that
  67. the CTB doesn't allow you to look at characters following a found
  68. CMSearch string, then gives my solution to this problem.
  69.  
  70. - --------------------------------------
  71.  
  72. You're not doing anything wrong that I know of.  The Comm Toolbox simply
  73. doesn't let you get at any text following your search.  Here's my theory
  74. why (but I don't know, so don't quote me to anyone important):
  75.  
  76. The connection tool transfers incoming text from the hardware buffer
  77. (4-byte SCC buffer, 64-byte serial buffer, or whatever) to its own larger
  78. buffer to hold until the application wants it.  While performing this
  79. transfer, moving one character at a time, it updates its search strings
  80. in the same manner that I have coded below.  When one of the strings
  81. gets found, it immediately calls your callback routine, without transfer-
  82. ring even another single character.
  83.  
  84. When you think about it, this makes sense.  You should not be able to get
  85. at characters further on in the buffer, as there is no definition to how
  86. many characters you would get.  It would make things substantially harder
  87. for the connection tool, because it would always have to read x many more
  88. characters after the string was found, and if the buffer overflowed, the
  89. entire search string and all chars afterwards would have to be shifted
  90. around to make room.
  91.  
  92. Not only that, but what standard would you make it?  Eight characters more
  93. after the string found?  Someone will need ten more.  Okay then, ten.  But
  94. what if someone needs fifty?  A hundred?  One K...  So, best to let the
  95. application handle searching itself if it needs these special requirements.
  96. I think the search function was only implemented to allow comm programs
  97. to recognize automatic file transfer requests as demoed in the sample app
  98. that came with the CTB developer's kit.
  99.  
  100. So, you're stuck without a standard and with no way to get at the next
  101. few characters after your search string.  The only solution I see is for
  102. you to write your own.  I did.  Here's my version (you'll have to change
  103. all serial calls to be CTB calls, but other than that it's straightforward).
  104.  
  105. Note that all of the strings used in this code are C strings, because
  106. they are far more buffer-friendly than Pascal strings.  Also, some of this
  107. code was changed so I could send it to you, but it should (SHOULD--I'm
  108. not certian that I didn't add bugs when I edited it) remain bug-free.
  109. It is currently in use in a commercial application that I wrote, so I
  110. hope it will work without a flaw...
  111.  
  112. // By Scott Bronson
  113. // 
  114. // The only structure used...
  115. typedef struct searchrec {
  116.     char *first, *cur;
  117. } searchrec;
  118.  
  119. // We can search for this many strings maximum:
  120. #define kNumSearches 16
  121.  
  122. // Global variables used...
  123. short numsearches = 0;
  124. long gStringFound;
  125. searchrec search[kNumSearches];
  126.  
  127. // This is my actual idle loop.  It should
  128. // be able to be used right out of the box.
  129. //
  130. // Idle process:
  131. // % read chars into inbuff
  132. // - strip the eighth bit
  133. // - check against current searches
  134. // - Strip newlines
  135. // - Write to OldLines buffer
  136. // - Put in our log file buffer
  137. // % flush log file buffer
  138.  
  139. void WhatMeIdle( void )
  140. {
  141.     char inbuff[64], outbuff[64];
  142.     // 64-byte input buffer.  The output buffer is used to store the 8th-bit
  143.     // and newline stripped data that we will be displaying on screen.  The
  144.     // search algorithm will not be hurt at all by the disappearance of the
  145.     // ouptut buffer.
  146.     
  147.     register char c; // indexes through each char in the input buffer.
  148.     long count;        // The number of characters read into inbuff.
  149.     long j;            // The number of characters in outbuff.
  150.     short i, l;        // Indexes for loops.
  151.     OSErr err;        // Stores possible errors returned by OS.
  152.     
  153.     err = SerGetBuf( inDriverRefNum, &count );
  154.     if( err == noErr && count > 0 ) {
  155.         if( count > 64 ) count = 64;
  156.         err = FSRead( inDriverRefNum, &count, inbuff );
  157.         
  158.         // Now inbuff is filled with the next (count) characters
  159.         // from the incoming data stream.
  160.         
  161.         if( err == noErr ) {
  162.             
  163.             // We'll loop through every character in the buffer...
  164.             for( i=0,j=0; i<count; i++ ) {
  165.                 c = inbuff[i] & 0x7F;
  166.                 
  167.                 // Now c contains the next 7-bit character.
  168.                 // Here is the search algorithm.  If there are
  169.                 // any searches pending, loop through them and
  170.                 // update the found character counts.
  171.                 
  172.                 if(numsearches) for( l=0; l<numsearches; l++ ) {
  173.                     if( c == *(search[l].cur++) ) {
  174.                         if( !*search[l].cur ) {
  175.                         
  176.                             // Ah!  We found a string.  Leave its index
  177.                             // in a global variable, clear all searches,
  178.                             // and finish reading the current buffer.
  179.                             // You can do whatever you want here.
  180.                             
  181.                             gStringFound = l+1;
  182.                             numsearches = 0;
  183.                         }
  184.                     } else search[l].cur = search[l].first;
  185.                 }
  186.                 
  187.                 // If c is a newline character, we're done with it.
  188.                 if( c == '\n' ) continue;
  189.                 
  190.                 // I performed some other actions here that were removed
  191.                 // for clarity.  Now all we have to do is store c in the
  192.                 // output buffer so it will get written to our disk file.
  193.                 
  194.                 outbuff[j++] = c;
  195.             } // end of for loop.
  196.             
  197.             // If we are storing the incoming data, then write it out.
  198.             if( gLogToFile && j ) {
  199.                 FSWrite( gLogFileRef, &j, outbuff );
  200.             }
  201.         }
  202.     } // else no chars to be read.    
  203. }
  204.  
  205.  
  206. // This is used to add a string to search for, same as CMAddSearch.
  207. // The string passed to AddSearch MUST remain untouched from the time
  208. // it is added until the time CheckStringFound returns a non-empty
  209. // string (meaning AddSearch doesn't make a copy of the string it is
  210. // passed--it just uses it in-place).
  211.  
  212. void AddSearch( char *cs )
  213. {
  214.     if( numsearches < kNumSearches ) {
  215.         search[numsearches].cur = search[numsearches].first = cs;
  216.         numsearches++;
  217.     } // else search buffer is full.
  218. }
  219.  
  220.  
  221. // This is called periodically to see if a string is found.  It is passed
  222. // the address of a buffer large enough to hold the longest of all the
  223. // strings that are currently being searched for.  The buffer will contain
  224. // the actual string found, or a 0-lenth string if none have been found yet.
  225.  
  226. void CheckStringFound( char *ss )
  227. {
  228.     if( gStringFound ) {
  229.         strcpy( ss, search[--gStringFound].first );
  230.     } else {
  231.         ss[0] = 0;
  232.     }
  233. }
  234.  
  235.  
  236. ---------------------------
  237.  
  238. From: kurisuto@chopin.udel.edu (Sean J. Crist)
  239. Subject: Free code:  Packing up strings into a STR#
  240. Date: 16 Dec 92 00:27:40 GMT
  241. Organization: University of Delaware
  242.  
  243. I wrote the following code as a part of a parser, where I had to store a
  244. lot of strings in a table.  Since storing strings as an array of Str255
  245. (255 bytes per string) was very wasteful of memory, I wrote this code to
  246. pack strings up into a handle with almost no memory overhead.
  247.  
  248. I believe that the structure I use is identical to that of STR# resources,
  249. but I haven't actually tried saving one of the resulting handles as a STR#
  250. and using GetIndString to see if it is completely identical or not. 
  251. There's really no need to do this, since I've provided a routine for
  252. extracting the strings back out of the handle.
  253.  
  254. I've tested the code pretty throroughly, but I'd appreciate hearing any
  255. bug reports.  Comments are welcome.  The code is in THINK Pascal 4.0.
  256.  
  257. - --Kurisuto
  258. kurisuto@chopin.udel.edu
  259.  
  260. unit STRpackaging;
  261.  
  262. {By Sean Crist}
  263.  
  264. {This code is for packing and unpacking strings in a compressed format
  265. like that of an STR#}
  266. {resource.  The strings are kept in a handle.  The first two bytes of this
  267. handle are the total }
  268. {number of strings.  Following are the strings themselves.  A Pascal
  269. string has the string length}
  270. {in the first byte followed by the characters themselves; if the length
  271. byte plus number of characters}
  272. {is an odd integer, we add an extra byte into the structure as packing.}
  273.  
  274. interface
  275.  
  276. {This function creates a new empty STR.  You should pass it an unallocated
  277. handle; this routine}
  278. {will allocate the handle and will return it in the same argument that you
  279. passed.  This function}
  280. {returns TRUE if the allocation was successful, FALSE if it couldn't
  281. allocate the memory (in which}
  282. {case you must gracefully deal with this failure).}
  283.  function CreateNewSTR (var TheSTR: Handle): Boolean;
  284.  
  285. {This function adds a new string to the end of a STR and returns its
  286. index.  TheSTR is a string}
  287. {handle you created with CreateNewSTR; TheString is the Pascal string
  288. which you want to add}
  289. {to this handle.  This function returns the index for the string in the
  290. list.  If memory cannot be}
  291. {allocated to expand the handle, -1 is returned.}
  292.  function AddToSTR (TheSTR: Handle; TheString: string): Integer;
  293.  
  294. {This function searches for a given string and returns its index.  It
  295. returns the index of the string;}
  296. {if it can't find a match for the string, it returns 0.}
  297.  function FindInSTR (TheSTR: Handle; TheString: string): Integer;
  298.  
  299. {This function, given an index, returns a string (much like GetIndString).
  300.  If TheIndex is not a valid}
  301. {index, then the empty string '' is returned.}
  302.  function ExtractSTR (TheSTR: Handle; TheIndex: Integer): Str255;
  303.  
  304. implementation
  305.  
  306.  procedure doOSErr (WhichError: Integer);
  307.  begin
  308. {You'd have to put whatever code you use to report an error here.}
  309. {My program puts up an alert with the error number as a ParamText argument.}
  310. {I've just included this here so that the unit will compile; this example
  311. is about}
  312. {packing up strings, not about reporting errors :-)  }
  313.  end;
  314.  
  315. {About the following four routines:  these routines are for compressing
  316. strings into}
  317. {an array with the same structure as a STR# resource.  This is a way to
  318. save a lot}
  319. {of memory which would go wasted if we stored lists of strings as arrays
  320. of Str255.}
  321.  
  322.  function CreateNewSTR (var TheSTR: Handle): Boolean;
  323.   var
  324.    TheNewSTR: Handle;
  325.  begin
  326.   TheNewSTR := NewHandle(2);   {Make a new handle the size of an integer.}
  327.   if MemError <> 0 then   {Check for MemError like good boys and girls}
  328.    begin
  329.     doOSErr(MemError);
  330.     CreateNewStr := false;   {Tell whoever called us that we've failed.}
  331.    end
  332.   else   {The memory was successfully allocated, so go ahead.}
  333.    begin
  334.     CreateNewStr := true;  {Tell whoever called us that we've succeeded.}
  335.     TheSTR := TheNewSTR;
  336.     StuffHex(TheNewSTR^, '0000');  {Initialize the number of strings to 0.}
  337.    end;
  338.  end;
  339.  
  340. {The following routine makes odd numbers into even numbers by adding one
  341. if necessary.}
  342.  function MakeEven (OddInteger: Integer): Integer;
  343.  begin
  344. {If this is an even integer...}
  345.   if OddInteger = ((OddInteger div 2) * 2) then
  346. {...then just return the number we were given...}
  347.    MakeEven := OddInteger
  348.   else
  349. {...but if this is an odd integer, add 1 to make it even.}
  350.    MakeEven := OddInteger + 1;
  351.  end;
  352.  
  353. {This function adds a new string to the end of a STR and returns its
  354. index.  If memory is}
  355. {insufficient, we return -1.}
  356.  function AddToSTR; {(TheSTR: Handle, TheString: string): Integer;}
  357.   var
  358.    OldNumberOfStrings, NewNumberOfStrings: Integer;
  359.    NewStringEvenLength, StringLength: Byte;
  360.    counter, CurrentOffset: Integer;
  361.    ScratchPtr: Ptr;
  362.    OldSize: LongInt;
  363.    OkSoFar: Boolean;
  364.  begin
  365.   OkSoFar := true;  {Let's assume everything's going to be all right.}
  366. {Figure out how big the old handle and the new string are.}
  367.   NewStringEvenLength := MakeEven(Length(TheString) + 1);  {+1 for size byte}
  368.   OldSize := GetHandleSize(TheSTR);
  369. {Set the size of the handle and check for errors.}
  370.   SetHandleSize(TheSTR, OldSize + NewStringEvenLength);
  371.   if MemError <> 0 then
  372.    begin
  373.     OkSoFar := false;
  374.     doOSErr(MemError);
  375.    end;
  376. {If everything is OK, then copy the new string into the handle.}
  377.   if OkSoFar then
  378.    begin
  379.     HLock(TheSTR);
  380.  
  381. {Figure out where the current end of the block is.}
  382.     BlockMove(TheSTR^, @OldNumberOfStrings, 2);
  383.     CurrentOffset := 2;
  384.     if OldNumberOfStrings > 0 then
  385.      for counter := 1 to OldNumberOfStrings do
  386.       begin
  387.        ScratchPtr := Ptr(LongInt(TheSTR^) + CurrentOffset);
  388.        StringLength := ScratchPtr^;
  389.        StringLength := MakeEven(StringLength + 1);
  390.        CurrentOffset := CurrentOffset + StringLength;
  391.       end;
  392.  
  393. {Copy the string into there.}
  394.     ScratchPtr := Ptr(LongInt(TheSTR^) + CurrentOffset);
  395.     BlockMove(@TheString, ScratchPtr, NewStringEvenLength);
  396.  
  397. {Update the count of strings.}
  398.     NewNumberOfStrings := OldNumberOfStrings + 1;
  399.     BlockMove(@NewNumberOfStrings, TheSTR^, 2);
  400.  
  401.     HUnlock(TheSTR);
  402.    end;
  403.  
  404.   AddToSTR := NewNumberOfStrings;
  405.   if not OkSoFar then
  406.    AddToSTR := -1;
  407.  end;
  408.  
  409. {This function searches for a given string and returns its index.  If we
  410. can't find it,}
  411. {we return 0.}
  412.  function FindInSTR; {(TheSTR:  Handle , TheString: string): Integer;}
  413.   var
  414.    Index, CurrentOffset, TopStrings: Integer;
  415.    StringLength: Byte;
  416.    CheckString: Str255;
  417.    done, foundIt: Boolean;
  418.    ScratchPtr: Ptr;
  419.  begin
  420.   Index := 0;
  421.   BlockMove(TheSTR^, @TopStrings, 2);  {Get the number of strings.}
  422.   CurrentOffset := 2;
  423.   done := false;
  424.   foundIt := false;
  425.   if TopStrings > 0 then
  426. {Loop through the strings until we find a match or until we've gone
  427. through them all.}
  428.    while not done do
  429.     begin
  430.      Index := Index + 1;
  431.      ScratchPtr := Ptr(LongInt(TheSTR^) + CurrentOffset);
  432.      StringLength := ScratchPtr^;
  433.      StringLength := MakeEven(StringLength + 1);
  434.      BlockMove(ScratchPtr, @CheckString, StringLength);
  435.      if EqualString(CheckString, TheString, false, true) then
  436.       begin
  437.        done := true;
  438.        foundIt := true;
  439.       end
  440.      else
  441.       begin
  442.        CurrentOffset := CurrentOffset + StringLength;
  443.       end;
  444.      if Index = TopStrings then
  445.       done := true;
  446.     end;
  447.   if FoundIt then
  448.    FindInSTR := Index
  449.   else
  450.    FindInStr := 0;
  451.  end;
  452.  
  453. {This function, given an index, returns a string.  If the index is out of
  454. range, we}
  455. {return an empty string.}
  456.  function ExtractSTR; {(TheSTR: Handle, TheIndex: Integer): Str255;}
  457.   var
  458.    CurrentOffset, TopStrings, counter: Integer;
  459.    StringLength: Byte;
  460.    TheString: Str255;
  461.    ScratchPtr: Ptr;
  462.  begin
  463.   BlockMove(TheSTR^, @TopStrings, 2);
  464.   CurrentOffset := 2;
  465.   TheString := '';
  466.   if (TopStrings > 0) and (TheIndex <= TopStrings) then
  467.    begin
  468.     for counter := 1 to TheIndex - 1 do
  469.      begin
  470.       ScratchPtr := Ptr(LongInt(TheSTR^) + CurrentOffset);
  471.       StringLength := ScratchPtr^;
  472.       StringLength := MakeEven(StringLength + 1);
  473.       CurrentOffset := CurrentOffset + StringLength;
  474.      end;
  475.     ScratchPtr := Ptr(LongInt(TheSTR^) + CurrentOffset);
  476.     StringLength := ScratchPtr^;
  477.     StringLength := MakeEven(StringLength + 1);
  478.     BlockMove(ScratchPtr, @TheString, StringLength);
  479.    end;
  480.   ExtractSTR := TheString;
  481.  end;
  482.  
  483.  
  484. end.
  485.  
  486. ---------------------------
  487.  
  488. From: GREMICF@YaleVM.YCC.Yale.Edu (M. David Greenspon)
  489. Subject: Machine Icons
  490. Date: 11 Dec 92 16:32:39 GMT
  491. Organization: Yale University
  492.  
  493. When you choose "About This Macintosh" from the Apple Menu in the finder, you
  494. get, among other things, an icon that looks like your machine.  These icons
  495. are stored as ICN#s in the System file.  When I call Gestalt with a selector
  496. of gestaltMachineIcon on my PB160, I get 49031; sure enough, ICN# 49031
  497. (= -16505) in the System file looks like a PowerBook.
  498.  
  499. Is there a list anywhere of Machine Icon numbers for _all_ Macs?  I don't have
  500. access to every kind of Mac ever made to go around running my program on.  In
  501. general, most of the icons do (sort of) look like the Macs I think they're
  502. supposed to represent, but in some cases I'm not sure exactly which is which.
  503. I'd like to be sure that I really am showing the "official" ones in all cases.
  504. The newest list of undocumented Gestalt stuff posted here doesn't say anything
  505. about this.  I can't find a Tech Note about it.  I'm doing this because I'd
  506. like to determine various things about the system I'm on:  for example, if I
  507. get an icon that looks like a Quadra, I'll assume the presence of an FPU.
  508.  
  509. Just kidding!  ;-) :-]  (I can just see the frantic letters pouring in from
  510. people who were too aghast to read further... ;~> )  I just want to display
  511. info about various Macs, and I thought it would be nice to display the icon.
  512. Thanks in advance for any info.
  513.  
  514. - --David
  515.  
  516. +++++++++++++++++++++++++++
  517.  
  518. From: Michael Hecht <Michael_Hecht@mac.sas.com>
  519. Date: Mon, 14 Dec 1992 15:37:07 GMT
  520. Organization: SAS Institute Inc.
  521.  
  522. In article <168BAA257.GREMICF@YaleVM.YCC.Yale.Edu> M. David Greenspon,
  523. GREMICF@YaleVM.YCC.Yale.Edu writes:
  524. >I'm doing this because I'd like to determine various things about the 
  525. >system I'm on:  for example, if I get an icon that looks like a Quadra, 
  526. >I'll assume the presence of an FPU.
  527.  
  528. Hah! Good one. Had me going there for a few seconds. :-)
  529.  
  530. Well, a little tracing with MacsBug reveals the following table that maps
  531. machine type to icon (for System 7.0.1*, anyway):
  532.  
  533. Machine Type                    Machine Icon
  534. ============                    ============
  535. unknown (0)                     3
  536. gestaltClassic (1)              -16482
  537. gestaltMacXL (2)                3
  538. gestaltMac512KE (3)             -16482
  539. gestaltMacPlus (4)              -16482
  540. gestaltMacSE (5)                -16483
  541. gestaltMacII (6)                -16486
  542. gestaltMacIIx (7)               -16486
  543. gestaltMacIIcx (8)              -16485
  544. gestaltMacSE030 (9)             -16483
  545. gestaltPortable (10)            -16484
  546. gestaltMacIIci (11)             -16485
  547. (12)                            3
  548. gestaltMacIIfx (13)             -16486
  549. (14)                            3
  550. (15)                            3
  551. (16)                            3
  552. gestaltMacClassic (17)          -16482
  553. gestaltMacIIsi (18)             -16502
  554. gestaltMacLC (19)               -16503
  555. (20)                            -16504
  556. (21)                            -16505
  557. (22)                            -16507
  558. (23)                            -16482
  559. (24)                            -16508
  560. (25)                            -16505
  561. (26)                            -16504
  562. (27)                            -16482
  563.  
  564. [Sorry, I don't have the machine names of the types above 19 handy at the
  565. moment.]
  566.  
  567. Of course, using this table as such has loads of problems:
  568.  
  569. * Apple could change the icon numbers on you.
  570.  
  571. * When new machine types are added, you'll never know about them.
  572.  
  573. To solve these problems, I suggest you take advantage of the fact that
  574. the machineIcon Gestalt selector calls the machineType gestalt selector
  575. to get the index into the above table. Use ReplaceGestalt to temporarily
  576. substitute the 'mach' selector with your own routine that will hand back
  577. whatever selector you want. Then, call Gestalt for the 'micn' repeatedly,
  578. and have your 'mach' function substitute a different machineType for each
  579. call.
  580.  
  581. You'll have to write your replacement Gestalt selector as a stand-alone
  582. code segment that loads into the System Heap. ReplaceGestalt complains,
  583. otherwise. You can store the fake machine selector somewhere near the
  584. beginning of it from your app, and just have the routine return it.
  585.  
  586. How do you know how many times to call? Fetch the kMachineNameStrID
  587. string list resource and see how many strings are in it!
  588.  
  589. Don't forget to replace the original 'mach' routine when you're done.
  590.  
  591. Good luck!
  592. - --Michael
  593.  
  594. PS: What are you writing?
  595.  
  596.  
  597. =======================================================================
  598. Michael P. Hecht                 | Internet:  Michael_Hecht@mac.sas.com
  599. SAS Institute Inc.; Cary, NC USA | AppleLink: SAS.HECHT
  600.  
  601. ---------------------------
  602.  
  603. From: kamprath@space-grant.sprl.umich.edu (Michael F. Kamprath)
  604. Subject: International Number Formats
  605. Date: 14 Dec 92 01:46:42 GMT
  606. Organization: University of Michigan, Aerospace Engineering
  607.  
  608. I'm trying to decipher IM VI with respect to how to convert a floating point
  609. number into a string to be displayed in the correct format (as set by the Nums&Date
  610. control panel) and vice versa (that is, strings --> numbers).  I'm not having much  
  611. luck.  Can anybody explain to me how to do this?  Thanks.
  612.  
  613. ======================================================================
  614. |Michael F. Kamprath                   | The University of Michigan  |
  615. |  kamprath@space-grant.sprl.umich.edu |      Aerospace Engineering  |
  616. |  kamprath@engin.umich.edu            |      Graduate Student       |
  617. ======================================================================
  618.  
  619. +++++++++++++++++++++++++++
  620.  
  621. From: wysocki@netcom.com (Chris Wysocki)
  622. Date: 15 Dec 92 05:02:12 GMT
  623. Organization: Connectix Corporation, San Mateo, CA
  624.  
  625. In article <4TS=Cj-@engin.umich.edu> Michael F. Kamprath <kamprath@space-grant.sprl.umich.edu> writes:
  626.  
  627. >I'm trying to decipher IM VI with respect to how to convert a floating point
  628. >number into a string to be displayed in the correct format (as set by the Nums
  629. >&Date control panel) and vice versa (that is, strings --> numbers).
  630.  
  631. Use the Script Manager routine Str2Format to convert a format string
  632. (such as "#,###,###;-#,###,###") to a canonical NumFormatString (which
  633. describes the format string in a script-independent manner), then use
  634. FormatX2Str and FormatStr2X to convert between 80-bit SANE extendeds
  635. and formatted strings.  You can obtain the necessary NumberParts table
  636. from the 'itl4' resource via:
  637.  
  638.     Handle      itl4H;
  639.     NumberParts parts;
  640.     
  641.     itl4H = IUGetIntl(4);
  642.     FailNILRes(itl4H);
  643.     parts = *(NumberParts *)(*itl4H + (**(Itl4Handle)itl4H).defPartsOffset);
  644.  
  645. The one trick is that you need to save the canonical NumFormatString
  646. returned by Str2Format in some way (e.g. in a resource), since
  647. Str2Format will interpret the format string differently depending on
  648. the current system environment (active script system, Numbers and
  649. Dates control panel settings, etc.)  To avoid this, write a throw-away
  650. program that calls Str2Format and saves the resulting NumFormatString
  651. in a resource.  Then, when you need to display a formatted number in
  652. your main program, get the saved NumFormatString resource, lock it
  653. down, and pass the dereferenced handle to FormatX2Str.  Complete
  654. details about Str2Format, FormatX2Str and FormatStr2X can be found in
  655. the Worldwide Guide to System Software stack, available on the
  656. developer CDs.
  657.  
  658. Chris.
  659. - -- 
  660. - ------------------------------------------------------------------------------
  661. Chris Wysocki                                     Internet: wysocki@netcom.com
  662. Software Engineer                                   America Online: AFA ChrisW
  663. Connectix Corporation                                   CompuServe: 72010,1140
  664.  
  665. ---------------------------
  666.  
  667. From: rmaag@iiic.ethz.ch (Rolf Maag)
  668. Subject: midi help needed
  669. Organization: Dept. Informatik, Swiss Federal Institute of Technology (ETH), Zurich, CH
  670. Date: Mon, 14 Dec 1992 15:29:50 GMT
  671.  
  672. hi there,
  673.  
  674. i am writing a midi-sequencing program with think c 4.0. i don't want to write my own midi-device driver, so can anyone tell me where i can get one? or maybe someone has a nice include file? anyway, thanx a lot and have fun..
  675.  
  676.  
  677. email to rmaag@iiic.ethz.ch
  678.  
  679. +++++++++++++++++++++++++++
  680.  
  681. From: steve@oceania.com
  682. Organization: Oceania Health Care Systems
  683. Date: Mon, 14 Dec 1992 21:18:50 GMT
  684.  
  685. Rolf Maag writes
  686.  
  687. > i am writing a midi-sequencing program with think c 4.0. i don't
  688. > want to write my own midi-device driver, so can anyone tell me where
  689. > i can get one? or maybe someone has a nice include file? anyway,
  690. > thanx a lot and have fun.. 
  691.  
  692. I don't think a 'nice include file' will do the trick.  MIDI is pretty  
  693. complex, being so time sensitive and all.
  694.  
  695. I have been using Apple's MIDIManager for about a year.  It works quite  
  696. well and only cost me $35.  It's a system extension that offers MIDI I/O  
  697. functions to any program that registers itself with the manager.  You use  
  698. an application that is included called PatchBay to connect MIDI input and  
  699. output devices/programs.
  700.  
  701. So far I have written one complete application with it and am on to my  
  702. second.  It has proven to be relatively simple and easy to use.
  703.  
  704. If anyone else is using it, please email me.  I'd like to know if anyone  
  705. would be able to use the programs I write with it if I released them as  
  706. freeware.
  707.  
  708. Good luck,
  709.  
  710. Steve
  711. - -- 
  712.           Steve Dakin           | 
  713.   Oceania Health Care Systems   |  That one deserves a ... WOW!
  714.  Palo Alto, CA  (415) 322-0127  |
  715.  steve@oceania.com (NeXT mail)  |  
  716.  
  717. ---------------------------
  718.  
  719. From: Daniel_R._Sandler@uu0570.foggybottom.com
  720. Organization: Foggy Bottom / Washington, D.C.
  721. Date: Wed, 09 Dec 1992 17:37:22 EST
  722. Subject: Background your Sound!
  723.  
  724. Okay, I've asked this before, and I haven't gotten an answer yet.  This means
  725. there are 3 possibilities:  either a) no one knoes how to do it (esp. not on
  726. my Classic); b) No one is responding; or c) whenevr you DO respond I miss the message
  727. because I do not log in soon enough and the message is flushed out of my BBS'
  728. temporary holding place for Inet newsgroup messages.
  729.  
  730. OK,ok, to the point:  How do I play sound while something else is ahppening,
  731. like so many games for the Mac, and even HyperCard?  If my games have to stop
  732. and pause to let a sound play, it really ruins the hole effect.
  733.  
  734. Thanks in advance.
  735.  
  736. dan
  737. 95dsandler@vax.mbhs.edu
  738. Daniel_R._Sandler@uu0570.foggybottom.com
  739.  
  740. Foggy Bottom - your FirstClass Mac connection in Washington, DC
  741.  
  742.  
  743. +++++++++++++++++++++++++++
  744.  
  745. From: werner@dewey.soe.berkeley.edu (John Werner)
  746. Date: 10 Dec 1992 17:42:07 GMT
  747. Organization: School of Education, U.C. Berkeley
  748.  
  749. In article <1992Dec09.173722.69189@uu0570.foggybottom.com> Daniel_R._Sandler@uu0570.foggybottom.com writes:
  750. >OK,ok, to the point:  How do I play sound while something else is ahppening,
  751. >like so many games for the Mac, and even HyperCard?  If my games have to stop
  752. >and pause to let a sound play, it really ruins the hole effect.
  753.  
  754. It's not that hard.  Use SndPlay, with the last "async" parameter set
  755. to TRUE.  The catch is that this only works if you're using your own
  756. sound channel.  So the code looks something like this:
  757.  
  758. SndChannelPtr myChannel;
  759. SndNewChannel(&myChannel, sampledSynth, 0, NULL);  /* Do once at startup */
  760.  .
  761.  .
  762. SndPlay(myChannel, mySound, TRUE);
  763.  .
  764.  .
  765. SndDisposeChannel(myChannel, TRUE);    /* Do this once at exit */
  766.  
  767. - -- 
  768. John Werner                        werner@soe.berkeley.edu
  769. UC Berkeley School of Education    510-642-9651
  770.  
  771. +++++++++++++++++++++++++++
  772.  
  773. From: k044477@hobbes.kzoo.edu (Jamie R. McCarthy)
  774. Organization: Kalamazoo College
  775. Date: Thu, 10 Dec 1992 21:03:23 GMT
  776.  
  777. werner@dewey.soe.berkeley.edu (John Werner) writes:
  778. >Daniel_R._Sandler@uu0570.foggybottom.com writes:
  779. >>
  780. >>OK,ok, to the point:  How do I play sound while something else is ahppening,
  781. >
  782. >It's not that hard.
  783.  
  784. Famous last words.  :-)  :-)
  785.  
  786. >Use SndPlay, with the last "async" parameter set
  787. >to TRUE.  The catch is that this only works if you're using your own
  788. >sound channel.  So the code looks something like this:
  789. >
  790. >SndChannelPtr myChannel;
  791.  
  792. Don't forget to set myChannel to NULL here.  Yeah, yeah, I know, this
  793. shouldn't be a problem.  But you never know.
  794.  
  795. If memory management concerns you, you'll want to be sure the SndChannel
  796. gets allocated in the right place.  If you let SndNewChannel do it for
  797. you, it'll essentially make a NewPtr() call.  By doing this yourself
  798. earlier in the program when the nonrelocatable block'll do less
  799. damage, or by making it a (locked!) handle that's moved hi, you can
  800. alleviate any problems.
  801.  
  802. Of course, the method given here will still work, if the fragmentation
  803. is not a concern.
  804.  
  805. >SndNewChannel(&myChannel, sampledSynth, 0, NULL);  /* Do once at startup */
  806. > .
  807. > .
  808. >SndPlay(myChannel, mySound, TRUE);
  809. > .
  810. > .
  811. >SndDisposeChannel(myChannel, TRUE);    /* Do this once at exit */
  812.  
  813.  
  814. If you allocate the memory yourself, you would instead write (for
  815. example):
  816.  
  817. SndChannel **mySndChannelHndl;
  818.  
  819. mySndChannelHndl = (SndChannel**) NewHandleClear(sizeof(SndChannel));
  820. // the "Clear" is _very_ important!
  821. (**mySndChannelHndl).qLength = stdQLength;
  822. MoveHHi((Handle) mySndChannelHndl);
  823. HLock((Handle) mySndChannelHndl);
  824.  
  825. ...later on...
  826.  
  827. SndNewChannel(*mySndChannelHndl, sampledSynth, initMono, NULL);
  828. SndPlay(*mySndChannelHndl, mySoundRsrc, TRUE);
  829. SndDisposeChannel(*mySndChannelHndl, TRUE);
  830.  
  831. ...and at app shutdown...
  832.  
  833. DisposHandle((Handle) mySndChannelHndl);
  834.  
  835. Two caveats.  (1) SndChannel's, like GrafPort's, must not move around
  836. (the system stores the list of them as a linked list of pointers).  If
  837. you do the handle thing, make sure it's locked.  (2) The Sound Manager
  838. compares the channel pointer that you pass it to its list, in an effort
  839. to find it.  (QuickDraw probably does the same thing with GrafPtr's.)
  840. So don't do anything silly like make the handle purgeable or (worse)
  841. unlocked--if you're in 24-bit mode, the hi byte of the master pointer
  842. will change, and the Sound Manager will suddenly not recognize it.
  843. Just lock it when it's created, leave it alone while you're using it,
  844. and you'll avoid both these problems.
  845. - -- 
  846.  Jamie McCarthy      Internet: k044477@kzoo.edu      AppleLink: j.mccarthy
  847.  "Apple developers will still have access to System 7.1 through the
  848.   monthly Developer CD series, but they may use it only for testing
  849.   and development purposes."              - AppleDirect, Nov/Dec 92
  850.  
  851. +++++++++++++++++++++++++++
  852.  
  853. From: ingemar@isy.liu.se (Ingemar Ragnemalm)
  854. Date: 11 Dec 92 12:38:53 GMT
  855. Organization: Dept of EE, University of Linkoping
  856.  
  857. werner@dewey.soe.berkeley.edu (John Werner) writes:
  858.  
  859. >In article <1992Dec09.173722.69189@uu0570.foggybottom.com> Daniel_R._Sandler@uu0570.foggybottom.com writes:
  860. >>OK,ok, to the point:  How do I play sound while something else is ahppening,
  861. >>like so many games for the Mac, and even HyperCard?  If my games have to stop
  862. >>and pause to let a sound play, it really ruins the hole effect.
  863.  
  864. >It's not that hard.  Use SndPlay, with the last "async" parameter set
  865. >to TRUE.  The catch is that this only works if you're using your own
  866. >sound channel.  So the code looks something like this:
  867.  
  868. (code deleted)
  869.  
  870. Speaking of asynchronous sound, what are the "rules" about several channels
  871. open at once? I have tried to make two channels for sampled sounds (on an
  872. LC), to play a sequence of notes on one of them (with a snd installed as
  873. "instrument") and various sound effects on the other. I get "not enough
  874. hardware". What information have I missed? Can't I have two sampled sound
  875. channels, or can't I use one of them for melodies?
  876.  
  877. What can be done and what can't when using several channels?
  878.  
  879. - -- 
  880. Ingemar Ragnemalm
  881. Dept. of Electrical Engineering         ...!uunet!mcvax!enea!rainier!ingemar
  882.                   ..
  883. University of Linkoping, Sweden         ingemar@isy.liu.se
  884.  
  885. +++++++++++++++++++++++++++
  886.  
  887. From: k044477@hobbes.kzoo.edu (Jamie R. McCarthy)
  888. Date: 11 Dec 92 21:53:00 GMT
  889. Organization: Kalamazoo College
  890.  
  891. ingemar@isy.liu.se (Ingemar Ragnemalm) writes:
  892. >
  893. >Speaking of asynchronous sound, what are the "rules" about several channels
  894. >open at once? I have tried to make two channels for sampled sounds on an
  895. >LC...  I get "not enough hardware".
  896.  
  897. I've heard this from other people, but I'll personally affirm that one
  898. can get two channels open on an LC.  Maybe if you showed us your code?
  899.  
  900. On my IIci, one "good-quality" channel takes about 18% of the CPU
  901. time.  I think it's a trifle over 30% on the LC.
  902.  
  903. "Good-quality" here means with both linear interpolation and drop-sample
  904. conversion.  Jim Reekes has indicated, however, that one of these is
  905. currently unimplemented (drop-sample conversion, I think).  He's also
  906. indicated that the CPU-time values returned by the S.M. are rather
  907. unreliable, so take the previous paragraph with a grain of salt.
  908. - -- 
  909.  Jamie McCarthy      Internet: k044477@kzoo.edu      AppleLink: j.mccarthy
  910.  "Apple developers will still have access to System 7.1 through the
  911.   monthly Developer CD series, but they may use it only for testing
  912.   and development purposes."              - AppleDirect, Nov/Dec 92
  913.  
  914. +++++++++++++++++++++++++++
  915.  
  916. From: edw@distant.uucp (Ed Watkeys)
  917. Date: 11 Dec 92 23:32:17 GMT
  918. Organization: Distant Software
  919.  
  920.  
  921. In article <ingemar.724077533@isy> (comp.sys.mac.programmer), ingemar@isy.liu.se (Ingemar Ragnemalm) writes:
  922. > werner@dewey.soe.berkeley.edu (John Werner) writes:
  923. > >In article <1992Dec09.173722.69189@uu0570.foggybottom.com> Daniel_R._Sandler@uu0570.foggybottom.com writes:
  924. > >>OK,ok, to the point:  How do I play sound while something else is ahppening,
  925. > >>like so many games for the Mac, and even HyperCard?  If my games have to stop
  926. > >>and pause to let a sound play, it really ruins the hole effect.
  927. > >It's not that hard.  Use SndPlay, with the last "async" parameter set
  928. > >to TRUE.  The catch is that this only works if you're using your own
  929. > >sound channel.  So the code looks something like this:
  930. > (code deleted)
  931. > Speaking of asynchronous sound, what are the "rules" about several channels
  932. > open at once? I have tried to make two channels for sampled sounds (on an
  933. > LC), to play a sequence of notes on one of them (with a snd installed as
  934. > "instrument") and various sound effects on the other. I get "not enough
  935. > hardware". What information have I missed? Can't I have two sampled sound
  936. > channels, or can't I use one of them for melodies?
  937. > What can be done and what can't when using several channels?
  938.  
  939. I think this is addressed in the Sound Manager chapter of IM VI. If I recall,
  940. you get a 'not enough hardware' error if you ask for too many channels with
  941. too high a quality. This is hardware dependent, of course. :)
  942.  
  943. Ed
  944.  
  945. > Ingemar Ragnemalm
  946.  
  947. - --
  948. Edwin H. Watkeys III                                   edw@distant.uucp
  949. Distant Software                               dsinc!jabber!distant!edw
  950. +1 215 387 7971                                     edw%distant@bts.com
  951.  
  952. +++++++++++++++++++++++++++
  953.  
  954. From: ldo@waikato.ac.nz (Lawrence D'Oliveiro, Waikato University)
  955. Date: 14 Dec 92 17:55:44 +1300
  956. Organization: University of Waikato, Hamilton, New Zealand
  957.  
  958. In article <1992Dec11.215300.2937@hobbes.kzoo.edu>, k044477@hobbes.kzoo.edu (Jamie R. McCarthy) writes:
  959. > ingemar@isy.liu.se (Ingemar Ragnemalm) writes:
  960. >>
  961. >>Speaking of asynchronous sound, what are the "rules" about several channels
  962. >>open at once? I have tried to make two channels for sampled sounds on an
  963. >>LC...  I get "not enough hardware".
  964. >
  965. > I've heard this from other people, but I'll personally affirm that one
  966. > can get two channels open on an LC.  Maybe if you showed us your code?
  967. >
  968. > On my IIci, one "good-quality" channel takes about 18% of the CPU
  969. > time.  I think it's a trifle over 30% on the LC.
  970.  
  971. It also depends on what you ask the channel to do. Playing a single channel
  972. of MACE compressed sound takes 48% of the CPU on my LC (or so the Sound
  973. Manager says). I can indeed play two such channels at once, and *everything*
  974. else on the machine (particularly screen drawing!) slows to a c-r-a-w-l.
  975.  
  976. With uncompressed sound, I have had 3 channels open at once with no problem,
  977. sometimes even 4. I think getting the 4th channel had something to do with
  978. not requesting sample-rate conversion, but it's been a while since I
  979. experimented with it. I remember getting that 30% figure when opening the
  980. first channel, but as I recall subsequent channels only increased the
  981. utilization by something like 18% each.
  982.  
  983. I managed to fool the Sound Manager once (I must figure out how to do it
  984. again) and open enough channels to take the CPU utilization over 100%.
  985. Things sort of ran, but it wasn't a great deal of fun. :-)
  986.  
  987. Lawrence D'Oliveiro                       fone: +64-7-856-2889
  988. Computer Services Dept                     fax: +64-7-838-4066
  989. University of Waikato            electric mail: ldo@waikato.ac.nz
  990. Hamilton, New Zealand    37^ 47' 26" S, 175^ 19' 7" E, GMT+13:00
  991.  
  992. ---------------------------
  993.  
  994. From: bpb9204@tamsun.tamu.edu (Brent Burton)
  995. Subject: Sound Input questions (real time usage)
  996. Date: 13 Dec 92 18:04:21 GMT
  997. Organization: Texas A&M Univ., Inc.
  998.  
  999.  
  1000. In short, I'm writing a program to draw the shape of the
  1001. sound coming in on the built-in device.  However, I'm new to
  1002. using the new Sound Manager and I don't know how to properly
  1003. approach it.
  1004.  
  1005. Think of my program as simply drawing a bar, which has a height
  1006. that is proportional to the sound level coming in, like a meter.
  1007.  
  1008. In IM-6, p 22-95, (talking about the sound parameter blocks), they
  1009. say that, "if the bufferPtr field contains NIL, then the count,
  1010.   milliseconds, and bufferLength fields are ignored, and the recording
  1011.   continues indefinitely until you cal SPBStopRecording.  If bufferPtr is
  1012.   NIL, the audio data is not saved anywhere; this feature is useful only
  1013.   if you want to do something in your interrupt routine and do not want
  1014.   to save the audio data." 
  1015.  
  1016. It says the data is not saved anywhere, but since I'm not interested in
  1017. saving any portion of the input stream (I want the current value only),
  1018. is there a location I can look to get the current digitized value?
  1019. Do I have to do this through the interrupt routine? 
  1020.  
  1021. Since my program is effectively a level meter, I just need the current
  1022. values.  Another approach I was thinking about was using a small buffer,
  1023. like << 100 bytes.  Since the buffer is small, the value contained in
  1024. it would be relatively close the the current value.  Is this feasible?
  1025.  
  1026. Anyway, if you have some ideas, please let me know.
  1027.  
  1028. thanks,
  1029. - -Brent
  1030.  
  1031. - -- 
  1032. +-------------------------+
  1033. | Brent Burton    N5VMG   |    
  1034. | bpb9204@tamsun.tamu.edu |  
  1035. +-------------------------+ 
  1036.  
  1037. +++++++++++++++++++++++++++
  1038.  
  1039. From: bpb9204@tamsun.tamu.edu (Brent Burton)
  1040. Date: 15 Dec 92 06:24:33 GMT
  1041. Organization: Texas A&M Univ., Inc.
  1042.  
  1043. bpb9204@tamsun.tamu.edu (Brent Burton) writes:
  1044. |
  1045. |Think of my program as simply drawing a bar, which has a height
  1046. |that is proportional to the sound level coming in, like a meter.
  1047. |
  1048. |Since my program is effectively a level meter, I just need the current
  1049. |values.  Another approach I was thinking about was using a small buffer,
  1050. |like << 100 bytes.  Since the buffer is small, the value contained in
  1051. |it would be relatively close the the current value.  Is this feasible?
  1052.  
  1053. I have learned a lot about the Sound Manager during the last few days,
  1054. and I have solved my problem.  
  1055.  
  1056. Essentially, what you would do is to call a routine, InitSound() for example,
  1057. to open the driver and begin recording.  You would then poll the device
  1058. to determine the current sound level whenever you needed to know the
  1059. sound level.  Finally, when you are done polling/using the device, you
  1060. call a routine such as KillSound() to stop recording and close the device.
  1061.  
  1062. This turned out to be simple, and brief pseudocode follows for the
  1063. routines:  (The code is from memory, so be sure to check, for instance,
  1064.   the parameter block's field names)
  1065.  
  1066. - ------------------------------------
  1067. #include <SoundInput.h>
  1068.  
  1069. long sndRefNum;
  1070.  
  1071. #define kAsynch TRUE
  1072.  
  1073. InitSound()
  1074. {
  1075.   OSErr e;
  1076.   SPB   s;
  1077.  
  1078.   e = SPBOpenDevice( NULL, siWritePermission, &sndRefNum);
  1079.   if ( e != noErr)
  1080.   {
  1081.     /** initialize the parameter block - fill in all fields - see IM 6 **/
  1082.     s.count =0;  s.milliseconds=0; s.buffPtr = NULL;  s.buffLen = 0;
  1083.     s.completionRoutine=NULL; s.interruptRoutine=NULL; 
  1084.     s.inRefNum = sndRefNum;          /* ... */
  1085.  
  1086.     e = SPBRecord( &s, kAsynch);  /* record asynchronously */
  1087.     if (e != noErr)
  1088.     {  /* error */  }
  1089.  
  1090.   } else { /* error */ }
  1091. } /* InitSound() */
  1092.  
  1093. /**** After InitSound() is called, you can poll the device to get 
  1094. ***** various characteristics about the recording.
  1095. **  Call SPBGetRecordingStatus()  (see inside mac 6)  to get
  1096. **  recording time so far, remaining, the current sound level on the
  1097. ** input, etc.
  1098. *****/
  1099.  
  1100. /** Once your are done with polling, call KillSound() to clean up **/
  1101. KillSound()
  1102. {
  1103.   OSErr e;
  1104.   e = SPBStopRecording( sndRefNum);
  1105.   e = SPBCloseDevice( sndRefNum);
  1106.   sndRefNum=0;
  1107. } /* killSound() */
  1108.  
  1109. - ----------------------------
  1110.  
  1111. Hope this can help someone else.  It works for me.
  1112.  
  1113. - -Brent
  1114.  
  1115. - -- 
  1116. +-------------------------+
  1117. | Brent Burton    N5VMG   |    
  1118. | bpb9204@tamsun.tamu.edu |  
  1119. +-------------------------+ 
  1120.  
  1121. ---------------------------
  1122.  
  1123. End of C.S.M.P. Digest
  1124. **********************
  1125.